#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "list.h"
#include "media.h"
#include "server.h"
#include "media.h"
#include "protocol.h"
#include <signal.h>
#include "log.h"

#define RTSP_URL "rtsp://admin:admin123@192.168.0.108:8554/cam/realmonitor?channel=1&subtype=0"
#define RTMP_URL "rtmp://localhost:7217/myapp/video19"

void list_test(void);
void socket_server_test(void);
void media_ffmpeg_test(void);
void protocol_test(void);
void log_test(void);

int main()
{
    log_set_level(LOG_TRACE);
//    list_test();

//    socket_server_test();

//    media_ffmpeg_test();

//    log_test();

    protocol_test();

    return 0;
}

uint8_t exit_thread1 = false;
uint8_t exit_thread2 = false;
uint8_t exit_thread3 = false;

void log_test(void)
{
//    log_set_file("./log.txt");

    log_fatal("test ");
//    log_set_call(false);
    log_error("test ");
    log_warning("test ");
    log_info("test ");
    log_set_level(LOG_TRACE);
    log_debug("test ");
    log_trace("test ");

    pthread_t tid1, tid2, tid3;
    extern void *log_test_thread_handler(void *arg);
    pthread_create(&tid1, NULL, log_test_thread_handler, "xxxxxxx");
    pthread_create(&tid2, NULL, log_test_thread_handler, "OOOOOOO");
    pthread_create(&tid3, NULL, log_test_thread_handler, "MMMMMMM");

    sleep(1);
    log_set_call(false);
    sleep(1);

//    log_trace("pthread 1 cancel: %d", pthread_cancel(tid1));
    exit_thread1 = true;
    pthread_join(tid1, NULL);
//    log_trace("pthread 2 cancel: %d", pthread_cancel(tid2));
    exit_thread2 = true;
//    log_trace("pthread 3 cancel: %d", pthread_cancel(tid3));
    exit_thread3 = true;
    pthread_join(tid2, NULL);
    pthread_join(tid3, NULL);
}

void log_test_thread_exit_handler(void *arg){
    log_debug("%s", __FUNCTION__);
}

void *log_test_thread_handler(void *arg)
{
    pthread_cleanup_push(log_test_thread_exit_handler, NULL);
    char *buf = (char *)arg;
    while (1) {
//        usleep(400);
//        pthread_testcancel();
        if (exit_thread1) {
            if (strcmp(buf, "xxxxxxx") == 0) {
                pthread_exit(0);
            }
        }
        if (exit_thread2) {
            if (strcmp(buf, "OOOOOOO") == 0) {
                pthread_exit(0);
            }
        }
        if (exit_thread3) {
            if (strcmp(buf, "MMMMMMM") == 0) {
                pthread_exit(0);
            }
        }
        // log_info called will be cause deadlock when call thread_cancel.
        log_info("hello world! %s", buf);
    }
    pthread_cleanup_pop(1);
}

void protocol_test(void)
{
    int ret = 0;
    media_t *media = media_ffmpeg_new();
    if (!media) {
        log_error("protocol register media error\n");
        exit(-1);
    }

    ret = protocol_register_media(media);
    if (ret) {
        log_error("protocol register media error\n");
        exit(-1);
    }

    socket_server_start("/tmp/unix_sock", protocol_msg_handle);

    char buf[128] = {0};
    while (fgets(buf, 128, stdin)) {
        if (strncmp(buf, "quit", 4) == 0) {
            log_info("\n exit by user\n");
            break;
        }
    }

    socket_server_stop();
    media_ffmpeg_delete(media);
}

void media_ffmpeg_test(void)
{
    media_t *media = media_ffmpeg_new();

    media->user_cmd(media, true, "ls -al");
    sleep(1);
    media->user_cmd(media, false, "");
    sleep(1);

    media->rtsp_to_rtmp(media, true, RTSP_URL, RTMP_URL, "");
    sleep(5);
    media->rtsp_to_rtmp(media, false, RTSP_URL, "", "");
    sleep(2);

    media->rtsp_to_rtmp(media, true, RTSP_URL, RTMP_URL, "720x480");
    sleep(2);

    remove("./img1.jpg");
    remove("./img2.jpg");
    remove("./img3.jpg");
    remove("./test.avi");
    media->rtsp_record(media, true, RTMP_URL, "./test.avi");

    sleep(10);

    if (media->rtsp_screenshot(media, RTMP_URL, "./img1.jpg") == MEDIA_RET_CMD_RUNNING) {
        log_error("error: screenshot cmd running.\n");
    }

    if (media->rtsp_screenshot(media, RTMP_URL, "./img2.jpg") == MEDIA_RET_CMD_RUNNING) {
        log_error("error: screenshot cmd running.\n");
    }

    if (media->rtsp_screenshot(media, RTMP_URL, "./img3.jpg") == MEDIA_RET_CMD_RUNNING) {
        log_error("error: screenshot cmd running.\n");
    }

    sleep(10);
    media->rtsp_record(media, false, "", "");
    sleep(2);
    media->rtsp_to_rtmp(media, false, "", "", "");

    char buf[2048] = {0};
    media->stream_probe(media, RTMP_URL, buf, 2048);
    log_info("\n\n\nbuf: \n%s\n\n\n", buf);

    sleep(4);
    media_ffmpeg_delete(media);

    system("stty echo");
}

int msg_to_do(const void *in, void *out, uint32_t out_len)
{
    char *in_buf = (char *)in;
    log_info("msg: %s\n", in_buf);
    strncpy((char *)out, in_buf, out_len - 1);
    return strlen(in_buf);
}

void socket_server_test(void)
{
    socket_server_start("/tmp/unix_sock", msg_to_do);

    sleep(10);
    log_debug("test: sockert server stop\n");
    socket_server_stop();
    log_debug("test: sockert server restart\n");
    socket_server_start("/tmp/unix_sock", msg_to_do);

    char input[128] = {0};
    while (1) {
        scanf("%s", input);
        if (strncmp(input, "quit", 4) == 0) {
            socket_server_stop();
            log_info("quit!\n");
            sleep(1);
            exit(0);
        }
        sleep(10);
    }
}

typedef struct {
    char name[100];
    int age;
} student_t;

bool traverse(void *node_data, void *data)
{
    student_t *node_stu = (student_t *)node_data;
    char *name = (char *)data;
    return strcmp(node_stu->name, name) == 0;
}

void print(void *node_data, void *data)
{
    student_t *stu = (student_t *)node_data;
    log_info("name: %s, age: %d\n", stu->name, stu->age);
}


void list_test(void)
{
    clist_t *list = clist_new();
    student_t stu1 = {
        .name = "hejiang",
        .age = 25
    };
    student_t stu2 = {
        .name = "duapple",
        .age = 18
    };
    student_t stu3 = {
        .name = "river",
        .age = 20
    };

    list->node_add(list, &stu1);
    list->node_add(list, &stu2);
    list->node_add(list, &stu3);

    list->list_traverse(list, NULL, print);
    log_info("\n\n");

    student_t stu4 = {
        .name = "serven",
        .age = 26
    };

    list->node_insert(list, &stu4, "duapple", traverse, true);
    list->list_traverse(list, NULL, print);
    log_info("\n\n");
    log_info("list len: %d\n", list->len);

    list->node_insert(list, &stu4, "hejiang", traverse, true);
    list->list_traverse(list, NULL, print);
    log_info("\n\n");
    log_info("list len: %d\n", list->len);

    list->node_insert(list, &stu4, "river", traverse, true);
    list->list_traverse(list, NULL, print);
    log_info("\n\n");
    log_info("list len: %d\n", list->len);

    list->node_add(list, &stu3);
    list->node_add(list, &stu3);
    list->node_add(list, &stu3);
    list->list_traverse(list, NULL, print);
    log_info("\n\n");
    log_info("list len: %d\n", list->len);

    list->node_remove(list);
    list->node_remove(list);
    list->node_remove(list);
    list->list_traverse(list, NULL, print);
    log_info("\n\n11111");
    log_info("list len: %d\n", list->len);

    list->node_add(list, &stu4);
    list->node_remove_by_data(list, "serven", traverse);
    list->node_remove_by_data(list, "serven", traverse);
    list->node_remove_by_data(list, "serven", traverse);
    list->node_remove_by_data(list, "serven", traverse);

    list->list_traverse(list, NULL, print);
    log_info("\n\n");
    log_info("list len: %d\n", list->len);

    list->list_del(list, NULL);

    log_info("end\n");
}
